﻿using System;
using System.Collections.Generic;
using System.Linq;

using agsXMPP;

using VSTalk.Engine.Core.Feed;
using VSTalk.Engine.Core.History;
using VSTalk.Engine.ViewModel.Messenger.ThreadRenderer;
using VSTalk.Engine.ViewModel.Messenger.ThreadRenderer.Command;

namespace VSTalk.Engine.ViewModel.Messenger.History
{
    public class HistoryLoaderViewModel
    {
        private static IHistoryService HistoryService
        {
            get { return AppServices.Get<IHistoryService>(); }
        }

        private readonly Guid _clientId;

        private readonly Jid _withEntity;

        private readonly ConversationThread _conversationThread;

        private List<TimeFrameParam> _timeFrames;

        private TimeFrameParam _currentFrame;

        public HistoryLoaderViewModel(Guid clientId, Jid withEntity, ConversationThread conversationThread)
        {
            _clientId = clientId;
            _withEntity = withEntity;
            _conversationThread = conversationThread;
        }

        public void Init()
        {
            _timeFrames = InitialFrames().ToList();
            if (!_timeFrames.Any())
            {
                return;
            }
            var message = new HistoryCommandMessage
            {
                Frames = _timeFrames,
                Callback = LoadHistory
            };
            var command = new RenderHistoryLoader(_conversationThread.Model, message);
            command.Execute();
        }


        private void LoadHistory(TimeFrameParam param)
        {
            var removeControl = new RemoveHistoryLoader(_conversationThread.Model);
            removeControl.Execute();
            
            RenderHistory(param);
            DisableTimeFrames(param);

            if (!_timeFrames.Last().Enabled)
            {
                return;
            }
            var message = new HistoryCommandMessage
            {
                Frames = _timeFrames,
                Callback = LoadHistory
            };

            var addControl = new RenderHistoryLoader(_conversationThread.Model, message);
            addControl.Execute();
        }

        private void RenderHistory(TimeFrameParam param)
        {
            IEnumerable<IMessage> messages;
            messages = _currentFrame == null 
                ? HistoryService.Read(_clientId, _withEntity, param.Span) 
                : HistoryService.Read(_clientId, _withEntity, param.Span, _currentFrame.Span);
            _currentFrame = param;
            foreach (var message in messages.Reverse())
            {
                var command = new RenderHistoryMessage(_conversationThread.Model, message);
                command.Execute();
            }
        }

        private void DisableTimeFrames(TimeFrameParam target)
        {
            foreach (var frameParam in _timeFrames)
            {
                frameParam.Enabled = false;
                if (frameParam == target)
                {
                    return;
                }
            }
        }

        private IEnumerable<TimeFrameParam> InitialFrames()
        {
            var latestDate = HistoryService.LatestMessageDate(_clientId, _withEntity);
            if (!latestDate.HasValue)
            {
                yield break;
            }
            var today = DateTime.Today;
            var testFrames = new List<TimeFrameParam>
            {
                new TimeFrameParam
                {
                    DisplayingValue = "Yesterday",
                    Span = today.AddDays(-1),
                },
                new TimeFrameParam
                {
                    DisplayingValue = "7 days",
                    Span = today.AddDays(-7)
                },
                new TimeFrameParam
                {
                    DisplayingValue = "30 days",
                    Span = today.AddDays(-30)
                },
                new TimeFrameParam
                {
                    DisplayingValue = "3 months",
                    Span = today.AddDays(-93)
                },
                new TimeFrameParam
                {
                    DisplayingValue = "6 months",
                    Span = today.AddDays(-186)
                },
                new TimeFrameParam
                {
                    DisplayingValue = "1 year",
                    Span = today.AddDays(-365)
                },
                new TimeFrameParam
                {
                    DisplayingValue = "From Beginning",
                    Span = DateTime.MinValue
                },
            };

            foreach (var timeFrameParam in testFrames)
            {
                yield return timeFrameParam;
                if (timeFrameParam.Span < latestDate.Value)
                {
                    yield break;
                }
            }
        }
    }
}